Break out code that was repeated into separate functions and call them
authorRichard Hult <richard@imendio.com>
Mon, 28 May 2007 21:11:55 +0000 (21:11 +0000)
committerRichard Hult <rhult@src.gnome.org>
Mon, 28 May 2007 21:11:55 +0000 (21:11 +0000)
2007-05-28  Richard Hult  <richard@imendio.com>

* gdk/quartz/gdkevents-quartz.c (get_child_coordinates_from_ancestor)
(get_ancestor_coordinates_from_child): Break out code that was
repeated into separate functions and call them instead.
(find_window_for_mouse_nsevent): Break out this from
find_window_for_nsevent to make the code clearer.
(find_window_for_nsevent): Use the above and fix the returned
coordinates in the process so that they are always relative the
found window, both for the normal case and during grabs. Still
needs fixing for the case where we get nsevents for a window other
than than grab window during grabs.

svn path=/trunk/; revision=17971

ChangeLog
gdk/quartz/gdkevents-quartz.c

index c33e70bc6b301b00c87d304cd8614f7824029b5e..11a57cf20c34cb242a6022b08945a0edc57012f5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2007-05-28  Richard Hult  <richard@imendio.com>
+
+       * gdk/quartz/gdkevents-quartz.c (get_child_coordinates_from_ancestor)
+       (get_ancestor_coordinates_from_child): Break out code that was
+       repeated into separate functions and call them instead.
+       (find_window_for_mouse_nsevent): Break out this from
+       find_window_for_nsevent to make the code clearer.
+       (find_window_for_nsevent): Use the above and fix the returned
+       coordinates in the process so that they are always relative the
+       found window, both for the normal case and during grabs. Still
+       needs fixing for the case where we get nsevents for a window other
+       than than grab window during grabs.
+
 2007-05-28  Richard Hult  <richard@imendio.com>
 
        * gdk/quartz/gdkevents-quartz.c (gdk_event_translate): Fix typo,
index 348c568893cb5445c9077e19acdfbb8ec7d9d92f..9748591cebca11d2bd3a787b58a3876bff96a0a6 100644 (file)
@@ -785,33 +785,136 @@ _gdk_quartz_events_update_cursor (GdkWindow *window)
     [nscursor set];
 }
 
-/* This function finds the correct window to send an event to,
- * taking into account grabs (FIXME: not done yet), event propagation,
- * and event masks.
+/* Translates coordinates from an ancestor window + coords, to
+ * coordinates that are relative the child window.
+ */
+static void
+get_child_coordinates_from_ancestor (GdkWindow *ancestor_window,
+                                    gint       ancestor_x,
+                                    gint       ancestor_y,
+                                    GdkWindow *child_window, 
+                                    gint      *child_x, 
+                                    gint      *child_y)
+{
+  GdkWindowObject *ancestor_private = GDK_WINDOW_OBJECT (ancestor_window);
+  GdkWindowObject *child_private = GDK_WINDOW_OBJECT (child_window);
+
+  while (child_private != ancestor_private)
+    {
+      ancestor_x -= child_private->x;
+      ancestor_y -= child_private->y;
+
+      child_private = child_private->parent;
+    }
+
+  *child_x = ancestor_x;
+  *child_y = ancestor_y;
+}
+
+/* Translates coordinates from a child window + coords, to
+ * coordinates that are relative the ancestor window.
+ */
+static void
+get_ancestor_coordinates_from_child (GdkWindow *child_window,
+                                    gint       child_x,
+                                    gint       child_y,
+                                    GdkWindow *ancestor_window, 
+                                    gint      *ancestor_x, 
+                                    gint      *ancestor_y)
+{
+  GdkWindowObject *child_private = GDK_WINDOW_OBJECT (child_window);
+  GdkWindowObject *ancestor_private = GDK_WINDOW_OBJECT (ancestor_window);
+
+  while (child_private != ancestor_private)
+    {
+      child_x += child_private->x;
+      child_y += child_private->y;
+
+      child_private = child_private->parent;
+    }
+
+  *ancestor_x = child_x;
+  *ancestor_y = child_y;
+}
+
+/* Given a mouse NSEvent, returns the window in which the pointer
+ * position from the event is. The returned coordinates are relative
+ * to the found window, and normal GDK coordinates, not Quartz.
  */
 static GdkWindow *
-find_window_for_event (NSEvent *nsevent, gint *x, gint *y)
+find_window_for_mouse_nsevent (NSEvent *nsevent,
+                              gint    *x_ret,
+                              gint    *y_ret)
+{
+  NSWindow *nswindow;
+  GdkWindow *toplevel;
+  NSPoint point;
+  gint x_tmp, y_tmp;
+  GdkWindow *found_window;
+
+  nswindow = [nsevent window];
+  toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
+
+  point = [nsevent locationInWindow];
+
+  x_tmp = point.x;
+
+  /* Flip the y coordinate. */
+  if (toplevel == _gdk_root)
+    y_tmp = _gdk_quartz_window_get_inverted_screen_y (point.y);
+  else
+    {
+      GdkWindowImplQuartz *impl;
+
+      impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl);
+      y_tmp = impl->height - point.y;
+    }
+
+  found_window = _gdk_quartz_window_find_child (toplevel, x_tmp, y_tmp);
+
+  /* Translate the coordinates so they are relative to the found
+   * window.
+   */
+  if (found_window)
+    get_child_coordinates_from_ancestor (toplevel,
+                                        x_tmp, y_tmp,
+                                        found_window,
+                                        &x_tmp, &y_tmp);
+
+  *x_ret = x_tmp;
+  *y_ret = y_tmp;
+
+  return found_window;
+}
+
+/* This function finds the correct window to send an event to, taking
+ * into account grabs, event propagation, and event masks.
+ */
+static GdkWindow *
+find_window_for_nsevent (NSEvent *nsevent, gint *x, gint *y)
 {
   NSWindow *nswindow = [nsevent window];
   NSEventType event_type = [nsevent type];
 
   if (!nswindow)
     return NULL;
-  /* Window where not created by GDK so the event should be handled by Quartz */
+
+  /* Window was not created by GDK so the event should be handled by Quartz. */
   if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]]) 
     return NULL;
-  
+
+  /* Synthesize crossing events when moving between child
+   * windows. Toplevels are handled with NSMouseEntered and
+   * NSMouseExited in the switch below.
+   */
   if (event_type == NSMouseMoved ||
       event_type == NSLeftMouseDragged ||
       event_type == NSRightMouseDragged ||
       event_type == NSOtherMouseDragged)
     {
-      GdkWindow *toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
-      NSPoint point = [nsevent locationInWindow];
       GdkWindow *mouse_window;
 
-      mouse_window = _gdk_quartz_window_find_child_by_point (toplevel, point.x, point.y, x, y);
+      mouse_window = find_window_for_mouse_nsevent (nsevent, x, y);
 
       if (!mouse_window)
        mouse_window = _gdk_root;
@@ -826,7 +929,6 @@ find_window_for_event (NSEvent *nsevent, gint *x, gint *y)
          if (current_mouse_window != mouse_window)
            {
              synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
-             
              _gdk_quartz_events_update_cursor (mouse_window);
            }
        }
@@ -846,73 +948,92 @@ find_window_for_event (NSEvent *nsevent, gint *x, gint *y)
     case NSRightMouseDragged:
     case NSOtherMouseDragged:
       {
-       GdkWindow *toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
-       NSPoint point = [nsevent locationInWindow];
        GdkWindow *mouse_window;
        GdkEventMask event_mask;
        GdkWindow *real_window;
 
-       if (_gdk_quartz_pointer_grab_window && !pointer_grab_owner_events)
+       /* From the docs for XGrabPointer:
+        *
+        * If owner_events is True and if a generated pointer event
+        * would normally be reported to this client, it is reported
+        * as usual. Otherwise, the event is reported with respect to
+        * the grab_window and is reported only if selected by
+        * event_mask. For either value of owner_events, unreported
+        * events are discarded.
+        *
+        * This means we first try the owner, then the grab window,
+        * then give up.
+        */
+       if (_gdk_quartz_pointer_grab_window)
          {
-           if (pointer_grab_event_mask & get_event_mask_from_ns_event (nsevent))
+           if (pointer_grab_owner_events)
              {
-               int tempx, tempy;
-               GdkWindowObject *w;
-               GdkWindowObject *grab_toplevel;
-
-               w = GDK_WINDOW_OBJECT (_gdk_quartz_pointer_grab_window);
-               grab_toplevel = GDK_WINDOW_OBJECT (gdk_window_get_toplevel (_gdk_quartz_pointer_grab_window));
+               mouse_window = find_window_for_mouse_nsevent (nsevent, x, y);
+               event_mask = get_event_mask_from_ns_event (nsevent);
+               real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
+               
+               if (mouse_window && real_window && mouse_window != real_window)
+                 get_ancestor_coordinates_from_child (mouse_window,
+                                                      *x, *y,
+                                                      real_window,
+                                                      x, y);
+
+               if (real_window)
+                 return real_window;
+             }
 
-               tempx = point.x;
-               tempy = GDK_WINDOW_IMPL_QUARTZ (grab_toplevel->impl)->height -
-                 point.y;
+           /* FIXME: This part needs some fixing, it doesn't return
+            * the right coordinates if the nsevent happens for a
+            * different window than the grab window.
+            */
+           if (pointer_grab_event_mask & get_event_mask_from_ns_event (nsevent))
+             {
+               GdkWindow *grab_toplevel;
+               NSPoint point;
+               int x_tmp, y_tmp;
 
-               while (w != grab_toplevel)
-                 {
-                   tempx -= w->x;
-                   tempy -= w->y;
+               grab_toplevel = gdk_window_get_toplevel (_gdk_quartz_pointer_grab_window);
+               point = [nsevent locationInWindow];
 
-                   w = w->parent;
-                 }
+               x_tmp = point.x;
+               y_tmp = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (grab_toplevel)->impl)->height - point.y;
 
-               *x = tempx;
-               *y = tempy;
+               get_child_coordinates_from_ancestor (grab_toplevel,
+                                                    x_tmp, y_tmp, 
+                                                    _gdk_quartz_pointer_grab_window,
+                                                    x, y);
 
                return _gdk_quartz_pointer_grab_window;
              }
-           else
-             {
-               return NULL;
-             }
-         }
 
-       if (!nswindow)
-         {
-           mouse_window = _gdk_root;
+           return NULL;
          }
-        else
+       else 
          {
-           mouse_window = _gdk_quartz_window_find_child_by_point (toplevel, point.x, point.y, x, y);
+           /* The non-grabbed case. */
+           mouse_window = find_window_for_mouse_nsevent (nsevent, x, y);
+           event_mask = get_event_mask_from_ns_event (nsevent);
+           real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
+           
+           /* We have to translate the coordinates if the actual
+            * window is different from the mouse window.
+            */
+           if (mouse_window && real_window && mouse_window != real_window)
+             get_ancestor_coordinates_from_child (mouse_window,
+                                                  *x, *y,
+                                                  real_window,
+                                                  x, y);
+
+           return real_window;
          }
-
-       event_mask = get_event_mask_from_ns_event (nsevent);
-       real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
-       
-       return real_window;
       }
       break;
       
     case NSMouseEntered:
       {
-       NSPoint point;
-       GdkWindow *toplevel;
        GdkWindow *mouse_window;
 
-       point = [nsevent locationInWindow];
-       toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
-       
-       mouse_window = _gdk_quartz_window_find_child_by_point (toplevel, point.x, point.y, x, y);
-       
+       mouse_window = find_window_for_mouse_nsevent (nsevent, x, y);
        synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
       }
       break;
@@ -1179,7 +1300,7 @@ gdk_event_translate (NSEvent *nsevent)
        }
     }
 
-  window = find_window_for_event (nsevent, &x, &y);
+  window = find_window_for_nsevent (nsevent, &x, &y);
 
   /* FIXME: During owner_event grabs, we don't find a window when there is a
    * click on a no-window widget, which makes popups etc still stay up. Need